home *** CD-ROM | disk | FTP | other *** search
- ; SCC interrupt handler for IBM-PC
-
- include pmacros.h
-
- ; variables from C
-
- dseg
- extvar sccvecloc,word
- extvar sccmaxvec,byte
- extvar sccpolltab,word
- ifdef LARGEDATA
- extvar sccchan,dword
- else
- extvar sccchan,word
- endif
- dsegend
-
- ; variables from pcint.asm
-
- dseg
- extvar sssave,word
- extvar spsave,word
- extvar intstk,byte
- dsegend
-
- extproc doret
-
- ; sccvec is the interrupt handler for SCC interrupts using INTACK
-
- pubproc sccvec
-
- cli ; this code is not re-entrant, so make sure it
- ; is not interrupted. some multi-taskers
- ; intercept interrupt handlers, so be careful!
-
- push ax ; save ax first.
- push ds ; save on user stack
- getds
- mov ds,ax
-
- mov sssave@,ss ; stash user stack context
- mov spsave@,sp
-
- mov ss,ax ; set up interrupt stack
- lea sp,intstk@
-
- push bx ; save user regs on interrupt stack
- push cx
- push dx
- push bp
- push si
- push di
- push es
-
- ifndef LARGEDATA
- mov es,ax ; small data assumes ES == DS
- endif
-
- if TURBO or MSC
- cld ; in case "movsb" or "movsw" is used
- endif
-
- ; Read SCC interrupt vector and check it
-
- sccint: mov dx,sccvecloc@
- out dx,al ; Generate INTACK
- jmp short d1 ; Delay
- d1: jmp short d2
- d2: jmp short d3
- d3: in al,dx ; Read the vector
- cmp al,sccmaxvec@ ; Check for a legal vector
- jnc clrret ; It should not be >= the maximum
- ; If it is, ignore the interrupt
-
- ; Extract channel number and status from vector. Determine handler address.
-
- mov bl,al ; Copy vector (need it later for status)
- shr bl,1 ; Discard least significant bit
- jc clrret ; It should not be a 1
- and bx,7ch ; Isolate channel number (and make word)
- xor bl,04h ; Toggle A/B channel bit
- ifdef LARGEDATA
- les si,sccchan@[bx] ; Read address of channel structure
- else
- shr bl,1 ; Discard another bit
- mov si,sccchan@[bx] ; Read address of channel structure
- endif
- test si,si ; Test for NULL
- je clrret ; No channel struct, ignore it
- and ax,06h ; Isolate status info from vector
- add ax,ax ; Make index in FAR PTR array
- mov bx,ax ; It must be in BX
-
- ; Call the handler (defined in C), with sccchan struct as a parameter
-
- pushes
- push si ; Put channel struct as a parameter
- ifdef LARGEDATA
- call dword ptr es:[bx+si] ; Call the handler
- else
- call dword ptr [bx+si] ; Call the handler
- endif
- pop si ; Get channel struct back
- popes
-
- ; Reset highest priority interrupt
-
- ifdef LARGEDATA
- mov dx,es:16[si] ; Get control register address
- else
- mov dx,16[si] ; Get control register address
- endif
- mov al,38h ; "Reset Highest IUS" opcode
- out dx,al ; to WR0
- jmp short d4 ; settling delay
- d4: jmp short d5
- d5:
-
- ; Determine if more interrupt requests are coming in from the SCCs
-
- jmp sccint ; keep trying until no vector returned
-
- ; Clear the ISR bit in the PIC and return from interrupt
-
- clrret: jmp doret@ ; execute code in pcint.asm
-
- pend sccvec
-
- ; sccnovec is the interrupt handler for SCC interrupts using polling
-
- pubproc sccnovec
-
- cli ; this code is not re-entrant, so make sure it
- ; is not interrupted. some multi-taskers
- ; intercept interrupt handlers, so be careful!
-
- push ax ; save ax first.
- push ds ; save on user stack
- getds
- mov ds,ax
-
- mov sssave@,ss ; stash user stack context
- mov spsave@,sp
-
- mov ss,ax ; set up interrupt stack
- lea sp,intstk@
-
- push bx ; save user regs on interrupt stack
- push cx
- push dx
- push bp
- push si
- push di
- push es
-
- ifndef LARGEDATA
- mov es,ax ; small data assumes ES == DS
- endif
-
- if TURBO or MSC
- cld ; in case "movsb" or "movsw" is used
- endif
-
- ; Find the SCC generating the interrupt by polling all attached SCCs
- ; reading RR3A (the interrupt pending register)
-
- sccintnv:
- lea si,sccpolltab@ ; Point to polling table
- sccpoll:
- mov dx,[si] ; Get chan A CTRL address
- inc si
- inc si
- test dx,dx ; End of table without finding it
- je clrret ; Then return from interrupt
- mov al,3 ; Select RR3A
- out dx,al
- jmp short d6 ; Delay
- d6: jmp short d7
- d7: jmp short d8
- d8: in al,dx
- test al,al ; Test if a nonzero IP here
- jnz sccip ; Yes, handle it
- inc si ; No, next A CTRL
- inc si
- jmp sccpoll
-
- ; Read SCC interrupt vector from RR2B, it should always be correct
- ; Extract channel number and status from vector. Determine handler address.
-
- sccip: mov dx,[si] ; Read B CTRL address
- mov al,2 ; Select RR2B
- out dx,al
- jmp short d9 ; Delay
- d9: jmp short d10
- d10: jmp short d11
- d11: in al,dx ; Read the vector
- mov bl,al ; Copy vector (need it later for status)
- shr bl,1 ; Discard least significant bit
- and bx,7ch ; Isolate channel number (and make word)
- xor bl,04h ; Toggle A/B channel bit
- ifdef LARGEDATA
- les si,sccchan@[bx] ; Read address of channel structure
- else
- shr bl,1 ; Discard another bit (sccchan=words)
- mov si,sccchan@[bx] ; Read address of channel structure
- endif
- test si,si ; Test for NULL
- je clrret ; No channel struct, ignore it
- and ax,06h ; Isolate status info from vector
- add ax,ax ; Make index in FAR PTR array
- mov bx,ax ; It must be in BX
-
- ; Call the handler (defined in C), with sccchan struct as a parameter
-
- pushes
- push si ; Put channel struct as a parameter
- ifdef LARGEDATA
- call dword ptr es:[bx+si] ; Call the handler
- else
- call dword ptr [bx+si] ; Call the handler
- endif
- pop si ; Remove parameter from stack
- popes
-
- ; Check for more interrupt pending bits
-
- jmp sccintnv
-
- pend sccnovec
-
- ; scctvec is called as the replacement timer tick interrupt handler every 55ms.
- ; it calls scctim() and then jumps to the original handler.
- ; when the constant SCC_HWTIMER is defined during compilation of SCC.C,
- ; we'll install it directly on the timer hardware interrupt, not on the
- ; timer-tick user-exit (int 1c) because some programs take over that one
- ; without saving and calling the original handler installed there...
- ; (also, Phil Karn points out the int 1c is sluggish when DoubleDos is running)
-
- extproc scctim
-
- pubproc scctvec
-
- cli ; this code is not re-entrant, so make sure it
- ; is not interrupted. some multi-taskers
- ; intercept interrupt handlers, so be careful!
-
- push ax ; save ax first.
- push ds ; save on user stack
- getds
- mov ds,ax
-
- mov sssave@,ss ; stash user stack context
- mov spsave@,sp
-
- mov ss,ax ; set up interrupt stack
- lea sp,intstk@
-
- push bx ; save user regs on interrupt stack
- push cx ; (only those not saved by C)
- push dx
- push es
-
- ifndef LARGEDATA
- mov es,ax ; small data assumes ES == DS
- endif
-
- call scctim@ ; call timer tick routine (in C)
-
- pop es ; restore everything
- pop dx
- pop cx
- pop bx
-
- mov ss,sssave@
- mov sp,spsave@ ; restore original stack context
- pop ds
- pop ax
-
- db 0eah ; opcode for a far jump
- pubvar sccotvec,<dw 0,0ffffh> ; original INT handler address
- ; is stored here by initialization code
-
- pend scctvec
-
- end
-